package com.fadis.cmd;

import com.fadis.FadisException;
import com.fadis.FadisLog;
import com.fadis.persist.AOFMgmr;
import com.fadis.protocol.CmdEncoder;
import com.fadis.protocol.ErrorString;
import com.fadis.FadisThread;
import com.fadis.protocol.Resp;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

public class CmdDispatcher {



    private static final Map<String, CmdInfo> cmdHandlers = new HashMap<>();
    static{

        cmdHandlers.put("ping", new CmdInfo(false, new CmdCommon.ping()));
        cmdHandlers.put("auth", new CmdInfo(false, new CmdCommon.auth()));
        cmdHandlers.put("del", new CmdInfo(true, new CmdCommon.del()));
        cmdHandlers.put("exists", new CmdInfo(false, new CmdCommon.exists()));
        cmdHandlers.put("expire", new CmdInfo(true, new CmdCommon.expire()));
        cmdHandlers.put("ttl", new CmdInfo(false, new CmdCommon.ttl()));
        cmdHandlers.put("pttl", new CmdInfo(false, new CmdCommon.pttl()));
        cmdHandlers.put("rename", new CmdInfo(true, new CmdCommon.rename()));
        cmdHandlers.put("persist", new CmdInfo(true, new CmdCommon.persist()));
        cmdHandlers.put("flushdb", new CmdInfo(true, new CmdCommon.flushdb()));
        cmdHandlers.put("flushall", new CmdInfo(true, new CmdCommon.flushall()));

        cmdHandlers.put("set", new CmdInfo(true, new CmdString.set()));
        cmdHandlers.put("setnx", new CmdInfo(true, new CmdString.setnx()));
        cmdHandlers.put("setex", new CmdInfo(true, new CmdString.setex()));
        cmdHandlers.put("psetex", new CmdInfo(true, new CmdString.psetex()));
        cmdHandlers.put("get", new CmdInfo(false, new CmdString.get()));
        cmdHandlers.put("getset", new CmdInfo(true, new CmdString.getset()));
        cmdHandlers.put("strlen", new CmdInfo(false, new CmdString.strlen()));
        cmdHandlers.put("append", new CmdInfo(true, new CmdString.append()));
        cmdHandlers.put("setrange", new CmdInfo(true, new CmdString.setrange()));
        cmdHandlers.put("getrange", new CmdInfo(false, new CmdString.getrange()));
        cmdHandlers.put("incr", new CmdInfo(true, new CmdString.incr()));
        cmdHandlers.put("incrby", new CmdInfo(true, new CmdString.incrby()));
        cmdHandlers.put("incrbyfloat", new CmdInfo(true, new CmdString.incrbyfloat()));
        cmdHandlers.put("decr", new CmdInfo(true, new CmdString.decr()));
        cmdHandlers.put("decrby", new CmdInfo(true, new CmdString.decrby()));
        cmdHandlers.put("mset", new CmdInfo(true, new CmdString.mset()));
        cmdHandlers.put("msetnx", new CmdInfo(true, new CmdString.msetnx()));
        cmdHandlers.put("mget", new CmdInfo(false, new CmdString.mget()));

        cmdHandlers.put("lpush", new CmdInfo(true, new CmdList.lpush()));
        cmdHandlers.put("lpushx", new CmdInfo(true, new CmdList.lpushx()));
        cmdHandlers.put("rpush", new CmdInfo(true, new CmdList.rpush()));
        cmdHandlers.put("rpushx", new CmdInfo(true, new CmdList.rpushx()));
        cmdHandlers.put("lpop", new CmdInfo(true, new CmdList.lpop()));
        cmdHandlers.put("rpop", new CmdInfo(true, new CmdList.rpop()));
        cmdHandlers.put("rpoplpush", new CmdInfo(true, new CmdList.rpoplpush()));
        cmdHandlers.put("lrem", new CmdInfo(true, new CmdList.lrem()));
        cmdHandlers.put("llen", new CmdInfo(false, new CmdList.llen()));
        cmdHandlers.put("lindex", new CmdInfo(false, new CmdList.lindex()));
        cmdHandlers.put("linsert", new CmdInfo(true, new CmdList.linsert()));
        cmdHandlers.put("lset", new CmdInfo(true, new CmdList.lset()));
        cmdHandlers.put("lrange", new CmdInfo(false, new CmdList.lrange()));
        cmdHandlers.put("ltrim", new CmdInfo(true, new CmdList.ltrim()));
        cmdHandlers.put("blpop", new CmdInfo(true, new CmdList.blpop()));
        cmdHandlers.put("brpop", new CmdInfo(true, new CmdList.brpop()));
        cmdHandlers.put("brpoplpush", new CmdInfo(true, new CmdList.brpoplpush()));

        cmdHandlers.put("hset", new CmdInfo(true, new CmdHash.hset()));
        cmdHandlers.put("hsetnx", new CmdInfo(true, new CmdHash.hsetnx()));
        cmdHandlers.put("hget", new CmdInfo(false, new CmdHash.hget()));
        cmdHandlers.put("hexists", new CmdInfo(false, new CmdHash.hexists()));
        cmdHandlers.put("hdel", new CmdInfo(true, new CmdHash.hdel()));
        cmdHandlers.put("hlen", new CmdInfo(true, new CmdHash.hlen()));
        cmdHandlers.put("hstrlen", new CmdInfo(false, new CmdHash.hstrlen()));
        cmdHandlers.put("hincrby", new CmdInfo(true, new CmdHash.hincrby()));
        cmdHandlers.put("hincrbyfloat", new CmdInfo(true, new CmdHash.hincrbyfloat()));
        cmdHandlers.put("hmset", new CmdInfo(true, new CmdHash.hmset()));
        cmdHandlers.put("hmget", new CmdInfo(false, new CmdHash.hmget()));
        cmdHandlers.put("hkeys", new CmdInfo(false, new CmdHash.hkeys()));
        cmdHandlers.put("hvals", new CmdInfo(false, new CmdHash.hvals()));
        cmdHandlers.put("hgetall", new CmdInfo(false, new CmdHash.hgetall()));


        cmdHandlers.put("sadd", new CmdInfo(true, new CmdSet.sadd()));
        cmdHandlers.put("sismember", new CmdInfo(false, new CmdSet.sismember()));
        cmdHandlers.put("spop", new CmdInfo(true, new CmdSet.spop()));
        cmdHandlers.put("srandmember", new CmdInfo(false, new CmdSet.srandmember()));
        cmdHandlers.put("srem", new CmdInfo(true, new CmdSet.srem()));
        cmdHandlers.put("smove", new CmdInfo(true, new CmdSet.smove()));
        cmdHandlers.put("scard", new CmdInfo(false, new CmdSet.scard()));
        cmdHandlers.put("smembers", new CmdInfo(false, new CmdSet.smembers()));
        cmdHandlers.put("sinter", new CmdInfo(false, new CmdSet.sinter()));
        cmdHandlers.put("sinterstore", new CmdInfo(true, new CmdSet.sinterstore()));
        cmdHandlers.put("sunion", new CmdInfo(false, new CmdSet.sunion()));
        cmdHandlers.put("sunionstore", new CmdInfo(true, new CmdSet.sunionstore()));
        cmdHandlers.put("sdiff", new CmdInfo(false, new CmdSet.sdiff()));
        cmdHandlers.put("sdiffstore", new CmdInfo(true, new CmdSet.sdiffstore()));

        cmdHandlers.put("zadd", new CmdInfo(true, new CmdZSet.zadd()));
        cmdHandlers.put("zscore", new CmdInfo(false, new CmdZSet.zscore()));
        cmdHandlers.put("zincrby", new CmdInfo(true, new CmdZSet.zincrby()));
        cmdHandlers.put("zcard", new CmdInfo(false, new CmdZSet.zcard()));
        cmdHandlers.put("zcount", new CmdInfo(false, new CmdZSet.zcount()));

        cmdHandlers.put("zrange", new CmdInfo(false, new CmdZSet.zrange()));
        cmdHandlers.put("zrevrange", new CmdInfo(false, new CmdZSet.zrevrange()));

        cmdHandlers.put("zrangebyscore", new CmdInfo(false, new CmdZSet.zrangebyscore()));
        cmdHandlers.put("zrevrangebyscore", new CmdInfo(false, new CmdZSet.zrangebyscore()));

        cmdHandlers.put("zrank", new CmdInfo(false, new CmdZSet.zrank()));
        cmdHandlers.put("zrevrank", new CmdInfo(false, new CmdZSet.zrevrank()));

        cmdHandlers.put("zrem", new CmdInfo(true, new CmdZSet.zrem()));
        cmdHandlers.put("zremrangebyrank",new CmdInfo(true,  new CmdZSet.zremrangebyrank()));
        cmdHandlers.put("zremrangebyscore",new CmdInfo(true,  new CmdZSet.zremrangebyscore()));

        cmdHandlers.put("zrangebylex", new CmdInfo(false, new CmdZSet.zrangebylex()));
        cmdHandlers.put("zlexcount",new CmdInfo(false,  new CmdZSet.zlexcount()));
        cmdHandlers.put("zremrangebylex", new CmdInfo(true, new CmdZSet.zremrangebylex()));

        cmdHandlers.put("zinterstore", new CmdInfo(true, new CmdZSet.zinterstore()));
        cmdHandlers.put("zunionstore", new CmdInfo(true, new CmdZSet.zinterstore()));

        cmdHandlers.put("pfadd", new CmdInfo(true, new CmdHyperLogLog.pfadd()));
        cmdHandlers.put("pfcount", new CmdInfo(false, new CmdHyperLogLog.pfcount()));
        cmdHandlers.put("pfmerge",new CmdInfo(true,  new CmdHyperLogLog.pfmerge()));

        cmdHandlers.put("bf.add", new CmdInfo(true, new CmdBloomFilter.bfadd()));
        cmdHandlers.put("bf.madd", new CmdInfo(true, new CmdBloomFilter.bfmadd()));
        cmdHandlers.put("bf.exists",new CmdInfo(false, new CmdBloomFilter.bfexists()));
        cmdHandlers.put("bf.mexists",new CmdInfo(false,  new CmdBloomFilter.bfmexists()));

    }


    /**
     * 运行一组命令 -- 管道，或者事务的情景
     * @param cmds
     * @return
     */
    public static String run(List<String> cmds) {

        Callable<String> c = new Callable<String>() {
            @Override
            public String call() throws Exception {


                return "OK";
            }
        };

        return FadisThread.runInRedisThread(c);

    }

    /**
     * 执行一条命令
     * @param cmd
     * @return
     */
    public static String run(String cmd){
        FadisActionFrame frame = Resp.parseToFrame(cmd);
        Callable<String> c = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return run(cmd, frame);
            }
        };

        return FadisThread.runInRedisThread(c);
    }

    public static String runInCurrentThread(String cmd){
        FadisActionFrame frame = Resp.parseToFrame(cmd);
        return run(cmd, frame);
    }

    private static String run(String cmd, FadisActionFrame frame){
        CmdInfo cmdInfo = cmdHandlers.get(frame.firstArg().toLowerCase());

        if(cmdInfo == null){
            return CmdEncoder.getDefault().encode(new ErrorString("cmd not found -- " + frame.firstArg()));
        }else{
            CmdHandler h = cmdInfo.handler;
            try {
                FadisLog.log("server执行：" + cmd.replace("\r\n", "/r/n"));
                String r = h.run(frame);
                if(cmdInfo.willChangeData){
                    AOFMgmr.save(frame.firstArg().toLowerCase(), cmd);
                }
                return r;
            }catch (FadisException e){
                return CmdEncoder.getDefault().encode(new ErrorString(e.getMsg()));
            }catch (Exception e){
                e.printStackTrace();
                return CmdEncoder.getDefault().encode(new ErrorString(e.getMessage()));
            }

        }
    }


}
